Extensible Markup Language (XML) is a meta-markup language that provides a format for describing structured data. XML is similar to HTML in that it is a tag-based language. By virtue of its tag-based nature, XML defines a strict tree structure or hierarchy. XML is a subset of Standard Generalized Markup Language (SGML) that provides a uniform method for describing and exchanging structured data in an open, text-based format, and delivers this data by use of standard HTTP protocol. XML utilizes the concepts of elements and namespaces. Compared to HTML, XML facilitates more precise declarations of content and more meaningful data across multiple platforms.
XML “elements” are structural constructs that consist of a start tag, an end or close tag, and the information or content that is contained between the tags. A start tag is formatted as “<tag name>” and an end tag is formatted as “</tag name>”. In an XML document, start and end tags can be nested within other start and end tags. All elements that occur within a particular element must have their start and end tags occur before the end tag of that particular element. This defines a strict tree-like structure that can be used to generate an XML document, or by an XML parser to organize and parse the XML document. Each element forms a node in this tree, and potentially has “child” or “branch” nodes. The child nodes represent any XML elements that occur within the start and end tags of the “parent” node.
XML accommodates an infinite number of data schemas. Within each schema, data is represented by element names. Each schema is able to define its own “dictionary” of element names, referred to as a “namespace.” Namespace identifiers are used within an XML document to qualify element names, thereby allowing the same names to be used within different schemas without accidental conflicts.
Namespace inheritance within an XML document allows non-qualified names to use “default” namespaces. The default namespace for any particular XML element is whatever namespace is applicable to the parent of the particular element. A namespace specification within an XML document is said to have a “scope” which includes all child nodes beneath the namespace specification.
Typically, XML documents get exchanged between different entities, such as client and server computers, in the form of requests and responses. A client might generate a request for information or a request for a certain server action, and a server might generate a response to the client that contains the information or confirms whether the certain action has been performed. Part of the document exchange process between clients and servers involves parsing the XML documents when they are received. In many cases, it is convenient to represent these XML documents in memory as a hierarchical tree structure. Once the hierarchical tree structure is built, the actual parsing process can begin. Consider the following exemplary XML code:
<orders xmlns:person=“http://www.schemas.org/people”xmlns:dsig=“http://dsig.org”><order><sold-to><person:name><person:last-name>Layman</person:last-name><person:first-name>Andrew</person:first-name></person:name></sold-to><sold-on>1997-03-17</sold-on><dsig:digital-signature>1234567890</dsig:digital-signature></order></orders>
This code includes two XML namespace declarations that are each designated with “xmlns”. The declarations include a prefix, e.g. “person” and “dsig” respectively, and the expanded namespace to which each prefix refers, e.g. “http://www.schemas.org/people”, and “http://dsig.org” respectively. This code tells any reader that if an element name begins with “dsig:” its meaning is defined by whoever owns the “http://www.dsig.org” namespace. Similarly, elements beginning with the “person:” prefix have meanings defined by the “http://www.schemas.org/people” namespace.
Namespaces ensure that element names do not conflict, and clarify who defined which term. They do not give instructions on how to process the elements. Readers still need to know what the elements mean and decide how to process them. Namespaces simply keep the names straight.
FIG. 1 shows how the structure of the above code can be represented in a hierarchical tree structure. In FIG. 1, all of the elements or nodes are set out in an exemplary tree that represents the XML document. Such a structure is typically constructed in memory, with each node containing all data necessary for the start and end tags of that node.
It has been typical in the past to build the entire tree structure, such as the one shown in FIG. 1, before parsing the XML document. For large XML documents, this can consume a great deal of memory and processor time. Thus, it would be desirable to avoid this process if at all possible.
XML parsers are used by various applications to process XML documents. Parsers must know what particular elements mean and how to process them. Tags from multiple namespaces can be mixed, which is essential with data coming from multiple sources across the Web. With namespaces, both elements could exist in the same XML-based document instance but could refer back to two different schemas, uniquely qualifying their semantics. Parsers typically take the form of a code library that can be used by developers in conjunction with higher level languages such as C++ or Java. Using functions provided by such a code library, developers can access the structure of an XML document, enumerate its elements and their attributes, and manipulate the information that is contained within the document's prolog. A simple example would be an XML parser utility that checks for “well-formed” or “valid” documents, and serves as the equivalent of an HTML syntax checker.
XML parsers typically read XML files or data streams and construct a hierarchically structured tree, such as the one appearing in FIG. 1, as a data structure in memory. The XML parser then typically hands off this data structure data to viewers and other applications for processing. So, in the example XML code discussed above, a parser would first build the entire tree structure that is shown in FIG. 1 prior to parsing the document. Only after the entire tree structure was built in memory would the parser begin to start parsing the document.
One problem that is associated with XML parsers such as this is that they have to build an entire hierarchically structured tree in memory before parsing the XML data stream that defined the tree. This approach is not efficient because of the demands it places on the memory that is required to store the tree structure and the speed with which information can be conveyed to a client. For example, this type of approach is not efficient for an application that is doing work in connection with a large quantity of XML data that might be streaming in at a relatively slow speed. Consider, for example, that a client asks a server for a list of all messages of a certain type that are in a certain folder. The entire message list is going to be returned by the server as one large data stream. If the client has to wait for the entire message list to be returned from the server, then the client cannot begin to display any portion of the list until all of the data has been received. This approach requires a large memory overhead (for storing the XML data and building the hierarchical tree structure) which, in turn, impacts the speed with which responses can be used by client applications.
In addition, server-side parsing can be slowed down when an XML data stream includes information that is not understood by the parser. Typically, the parser must process this information regardless of whether it is understood or not.
This invention arose out of concerns associated with providing improved XML parsers and methods of parsing XML data streams that reduce memory overhead and increase the speed with which XML data can be provided and used by a client.